from typing import TYPE_CHECKING
from common.npc import Npc
from common.world import LatticeMap
from gui.reference import html_table
from gui.signals import SIGNALS
from utils.db import DBSession
from utils.reference import ConstItem

if TYPE_CHECKING:
    from common.player.reference import Player

class QuestCategory:
    Main = ConstItem('main', '主线')
    Side = ConstItem('side', '支线')


class QuestStatus:
    Finished = ConstItem('finished', '已完成')
    InProcess = ConstItem('in_process', '进行中')
    Accessible = ConstItem('accessible', '可接取')


class Quest:
    __slots__ = [
        'name', 'title', 'desc', 'category', 'ok', 'requirement',
        'rewards', 'status', 'objective', '_type',
    ]

    def __init__(self, name, **kwargs):
        self.name = name
        self.title = kwargs['title']
        self.desc = kwargs['desc']
        self.category = kwargs['category']
        self._type = kwargs['type']
        self.ok = False
        self.requirement = kwargs.get('requirement', None)
        self.objective = kwargs['objective']
        self.rewards = kwargs.get('rewards', None)
        self.status = None

    def do_finished(self, player: 'Player'):
        self.status = QuestStatus.Finished

    def label(self):
        result = '<span style="color:{style};font-family:SimHei;font-size:15pt;">({category})  {title}</span>'.format(
            category=self.category, style=self.color(), title=self.title
        )
        if self.ok and self.status == QuestStatus.InProcess:
            result += ' <span style="color:green">(可完成)</span>'

        return result

    def html(self):
        return f'<h2>{self.desc}<h2><h3>任务要求</h3>' + self.objective_html() + self.rewards_html()

    def color(self):
        if self.category == QuestCategory.Main:
            return 'red'
        else:
            return 'black'

    def player_interaction(self, player: 'Player'):
        if self.status is None:
            return

        if self.status != QuestStatus.InProcess or self.ok:
            return

        self.ok = self.check(player)
        if self.ok:
            SIGNALS.send_message.emit(f'任务：【<span style="color:{self.color()}">{self.title}</span>】 已完成')

    def objective_html(self):
        return ''

    def rewards_html(self):
        text = '<h3>任务奖励</h3>'
        reward_rows = []
        for key, meta in self.rewards.items():
            if key == 'equipment':
                equip = DBSession.equipments[meta]
                reward_rows.append(('装备', equip['name']))
            else:
                reward_rows.append(('金币' if key == 'coin' else '经验', meta))

        return text + html_table(reward_rows)

    def check(self, player: 'Player'):
        return False


class QuestMove(Quest):
    __slots__ = Quest.__slots__

    def objective_html(self):
        lm: LatticeMap = DBSession.lattice_map[self.objective['target_map']]
        objective_rows = [('目标地图', lm.name)]
        if quest_npc := DBSession.npc_map[self.objective['target_npc']]:
            objective_rows.append(('目标人物', quest_npc.name))
        return html_table(objective_rows)

    def check(self, player: 'Player'):
        lattice_map: LatticeMap = player.get_local_map()
        _npc: Npc = lattice_map.get_npc(player.pos)

        # 如果不在目标地图，直接返回False
        if self.objective['target_map'] != player.map_name:
            return False

        # 如果目标npc为None，说明只要在地图就行
        if self.objective['target_npc'] is None:
            return True

        # 检查npc是否匹配
        return _npc and _npc.key == self.objective['target_npc']


class QuestCollect(Quest):
    __slots__ = Quest.__slots__ + ['target_npc']

    def __init__(self, name, **kwargs):
        self.target_npc = kwargs.pop('target_npc')
        super().__init__(name, **kwargs)

    def do_finished(self, player: 'Player'):
        data = [(0, 'material', key, quantity) for key, quantity in self.objective.items()]
        if player.bag.update(data):
            self.status = QuestStatus.Finished

    def objective_html(self):
        objective_rows = [('目标人物', DBSession.npc_map[self.target_npc])]
        objective_rows.extend((DBSession.materials[k].name, v) for k, v in self.objective.items())
        return html_table(objective_rows)

    def check(self, player: 'Player'):
        result = True
        for key, quantity in self.objective.items():
            if key not in player.bag.material:
                return False

            result &= quantity <= player.bag.material[key]

        return result
